package com.zzyl.nursing.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.domain.Room;
import com.zzyl.nursing.mapper.RoomMapper;
import com.zzyl.nursing.service.IRoomService;
import com.zzyl.nursing.vo.RoomVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 房间Service业务层处理
 *
 * @author ruoyi
 * @date 2024-04-26
 */
@Service
public class RoomServiceImpl extends ServiceImpl<RoomMapper, Room> implements IRoomService {
    @Autowired
    private RoomMapper roomMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 查询房间
     *
     * @param id 房间主键
     * @return 房间
     */
    @Override
    public Room selectRoomById(Long id) {
        return getById(id);
    }

    /**
     * 查询房间列表
     *
     * @param room 房间
     * @return 房间
     */
    @Override
    public List<Room> selectRoomList(Room room) {
        return roomMapper.selectRoomList(room);
    }

    /**
     * 新增房间
     *
     * @param room 房间
     * @return 结果
     */
    @Override
    public int insertRoom(Room room) {
        return save(room) ? 1 : 0;
    }

    /**
     * 修改房间
     *
     * @param room 房间
     * @return 结果
     */
    @Override
    public int updateRoom(Room room) {
        return updateById(room) ? 1 : 0;
    }

    /**
     * 批量删除房间
     *
     * @param ids 需要删除的房间主键
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteRoomByIds(Long[] ids) {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 根据楼层 id 获取房间视图对象列表
     *
     * @param floorId 楼层 id
     * @return List<RoomVo>
     */
    @Override
    public List<RoomVo> getRoomsByFloorId(Long floorId) {
        return roomMapper.selectByFloorId(floorId);
    }


    /**
     * 获取所有房间（负责老人）
     *
     * @param floorId 楼层 id
     * @return List<RoomVo>
     */
    @Override
    public List<RoomVo> getRoomsWithNurByFloorId(Long floorId) {
        return roomMapper.selectByFloorIdWithNur(floorId);
    }

    /**
     * 根据房间 id 查询楼层，房间，价格
     *
     * @param id 房间 id
     * @return RoomVo
     */
    @Override
    public RoomVo one(Long id) {
        return roomMapper.getOneByRoomId(id);
    }

    /**
     * 根据楼层 id 获取房间视图对象列表(智能设备)
     *
     * @param floorId 楼层 id
     * @return List<RoomVo>
     */
    @Override
    public List<RoomVo> getRoomsWithDeviceByFloorId(Long floorId) {
        // 1.获取楼层的房间、床位、老人、设备信息
        List<RoomVo> roomVos = roomMapper.selectRoomsWithDeviceByFloorId(floorId);

        // 2.获取设备数据
        roomVos.forEach(roomVo -> {
            // 获取房间设备数据
            roomVo.getDeviceVos().forEach(deviceInfo -> {
                String jsonStr = (String) redisTemplate.opsForHash()
                                                       .get(CacheConstants.IOT_DEVICE_LAST_DATA, deviceInfo.getIotId());
                if (StringUtils.isEmpty(jsonStr)) {
                    return;
                }
                deviceInfo.setDeviceDataVos(JSONUtil.toList(jsonStr, DeviceData.class));
            });
            // 获取床位设备数据
            roomVo.getBedVoList().forEach(bedVo -> bedVo.getDeviceVos().forEach(deviceInfo -> {
                String jsonStr = (String) redisTemplate.opsForHash()
                                                       .get(
                                                               CacheConstants.IOT_DEVICE_LAST_DATA,
                                                               deviceInfo.getIotId()
                                                           );
                if (StringUtils.isEmpty(jsonStr)) {
                    return;
                }
                deviceInfo.setDeviceDataVos(JSONUtil.toList(jsonStr, DeviceData.class));
            }));
        });
        return roomVos;
    }

    /**
     * 根据楼层 id 获取房间视图对象列表(智能设备) --- redis优化版
     *
     * @param floorId 楼层 id
     * @return List<RoomVo>
     */
    @Override
    public List<RoomVo> getRoomsWithDeviceByFloorId2(Long floorId) {
        // 1.获取基础数据
        List<RoomVo> roomVos = roomMapper.selectRoomsWithDeviceByFloorId(floorId);

        // 2.收集所有设备iotId（确保是String类型）
        List<String> iotIds = new ArrayList<>();
        roomVos.forEach(roomVo -> {
            roomVo.getDeviceVos().forEach(device -> iotIds.add(device.getIotId()));
            roomVo.getBedVoList().forEach(bedVo ->
                                                  bedVo.getDeviceVos()
                                                       .forEach(device -> iotIds.add(device.getIotId()))
                                         );
        });

        // 3.批量查询Redis（关键修正点），Java在编译时期，会进行类型擦除，因此此处redisTemplate需要显式指定类型
        List<String> deviceDataList = redisTemplate.<String, String>opsForHash()
                                                   .multiGet(CacheConstants.IOT_DEVICE_LAST_DATA, iotIds);

        // 4.构建映射关系
        Map<String, List<DeviceData>> deviceDataMap = new HashMap<>();
        for (int i = 0; i < iotIds.size(); i++) {
            String jsonStr = deviceDataList.get(i);
            if (!StringUtils.isEmpty(jsonStr)) {
                deviceDataMap.put(iotIds.get(i), JSONUtil.toList(jsonStr, DeviceData.class));
            }
        }

        // 5.填充数据
        roomVos.forEach(roomVo -> {
            roomVo.getDeviceVos().forEach(device ->
                                                  device.setDeviceDataVos(
                                                          deviceDataMap.get(device.getIotId()))
                                         );
            roomVo.getBedVoList().forEach(bedVo ->
                                                  bedVo.getDeviceVos().forEach(device ->
                                                                                       device.setDeviceDataVos(
                                                                                               deviceDataMap.get(
                                                                                                       device.getIotId()))
                                                                              )
                                         );
        });

        return roomVos;
    }


}
